﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Kocic.RepositoryManagement.EntityFramework4;
using Kocic.RepositoryManagement;
using Sample.EF4.Model;
using Sample.Run.EntityFramework4;

namespace Sample.Run
{
    public static class EF4Samples
    {
        public static void Run()
        {
            #region Cleanup
            Console.WriteLine("Entity Framework 4 Samples ---------------------------\n");

            //Remove any existing data
            using (new EntityExecutionContext<SampleDataModelEntities>())
            {
                EntityRepositoryManager<Sample.EF4.Model.Person, SampleDataModelEntities>.DeleteEntityObjects(p => p);
            }
            #endregion

            #region Example #1 : Basic Context Invocation and Person Creation
            SampleDataModelEntities context = new SampleDataModelEntities();

            Console.WriteLine("Example: #1 ------------------------------------------");

            //Create instance of person manager and delete it right after. PersonManager disposes the context immediatly after existing this code block.
            using (Sample.Run.EntityFramework4.PersonRepositoryManager personManager = new Sample.Run.EntityFramework4.PersonRepositoryManager(context))
            {
                //Event subscribing
                personManager.Created += manager_EntityFrameworkCreated;
                personManager.Deleted += manager_EntityFrameworkDeleted;

                //Create new person
                Sample.EF4.Model.Person p1 = new Sample.EF4.Model.Person();
                p1.FirstName = "Nikola";
                p1.MiddleName = "Vlajko";
                p1.LastName = "Kocic";
                p1.Age = 29;

                //Create person - Implicit call.
                personManager.Save(p1);

                //Delete person
                personManager.Delete(p1);
            }

            #endregion

            #region Example #2 : Using the EntityExecutionContext
            Console.WriteLine("\n\nExample: #2 ------------------------------------------");

            using (new EntityExecutionContext<SampleDataModelEntities>())
            {
                //Create instance of person manager and delete it right after. PersonManager uses the single instance of the context as specified in the EntityExecutionContext
                using (Sample.Run.EntityFramework4.PersonRepositoryManager personManager = new Sample.Run.EntityFramework4.PersonRepositoryManager())
                {
                    //Event subscribing
                    personManager.Created += manager_EntityFrameworkCreated;
                    personManager.Deleted += manager_EntityFrameworkDeleted;
                    personManager.Updated += manager_EntityFrameworkUpdated;

                    //Create new person
                    Sample.EF4.Model.Person p1 = new Sample.EF4.Model.Person();
                    p1.FirstName = "Nikola";
                    p1.MiddleName = "Vlajko";
                    p1.LastName = "Kocic";

                    //Create person - Implicit call.
                    personManager.Save(p1);

                    p1.Age = 29;

                    //Update person - Implicit call.
                    personManager.Save(p1);

                    //Delete person
                    personManager.Delete(p1);
                }
            }

            #endregion

            #region Example #3 : Deferring Operations
            Console.WriteLine("\n\nExample: #3 ------------------------------------------");

            using (new EntityExecutionContext<SampleDataModelEntities>())
            {
                Person p;
                Person p2;

                using (Sample.Run.EntityFramework4.PersonRepositoryManager createManager = new Sample.Run.EntityFramework4.PersonRepositoryManager())
                {
                    //Defer all data operations until exit of code block
                    using (new EntityContextDeferrer<SampleDataModelEntities>())
                    {
                        //Subscribe to creating event instead of Created since operation is being deferred
                        createManager.Creating += manager_EntityFrameworkCreating;
                        p = new Sample.EF4.Model.Person();
                        p.FirstName = "Nikola";
                        p.LastName = "Kocic";

                        createManager.Save(p);

                        p2 = new Sample.EF4.Model.Person();
                        p2.FirstName = "John";
                        p2.LastName = "Doe";

                        createManager.Save(p2);

                        Console.WriteLine("Before Deferral: Person count in database: " + createManager.RetrieveMultiple().ToList().Count.ToString());
                    }
                    Console.WriteLine("After Deferral: Person count in database: " + createManager.RetrieveMultiple().ToList().Count.ToString());
                }

                using (Sample.Run.EntityFramework4.PersonRepositoryManager deleteManager = new Sample.Run.EntityFramework4.PersonRepositoryManager())
                {
                    //Subscribe to deleting event instead of Deleted since operation is being deferred
                    deleteManager.Deleting += manager_EntityFrameworkDeleting;

                    deleteManager.Delete(p);
                    deleteManager.Delete(p2);

                    Console.WriteLine("After Deferral: Person count in database: " + deleteManager.RetrieveMultiple().ToList().Count.ToString());
                }
            }

            #endregion

            #region Example #4 : Creating and Deleting a Person Entity Across Two Different Contexts
            Console.WriteLine("\n\nExample: #4 ------------------------------------------");

            Sample.EF4.Model.Person person4;
            using (new EntityExecutionContext<SampleDataModelEntities>())
            {
                using (Sample.Run.EntityFramework4.PersonRepositoryManager manager = new Sample.Run.EntityFramework4.PersonRepositoryManager())
                {
                    Sample.EF4.Model.Person temp;
                    manager.Created += manager_EntityFrameworkCreated;

                    temp = new Sample.EF4.Model.Person();
                    temp.FirstName = "Nikola";
                    temp.MiddleName = "Vlajko";
                    temp.LastName = "Kocic";

                    manager.Save(temp, SaveMethod.Create);  //Explicitly specify save method

                    person4 = manager.RetrieveSingle("Nikola", "Kocic");
                }
            }

            //At this point person4 instance doesn't belong to the same context below and the ObjectStateManager will not be able to find it.
            //Because of this, the PreDelete operation is implemented in the PersonManager class which first checks to see if the object is removed (Detached or doesn't have a state entry
            //in the ObjectStateManager) and if so it fetches the object, thus re-attaching it to this context.
            using (Sample.Run.EntityFramework4.PersonRepositoryManager manager = new Sample.Run.EntityFramework4.PersonRepositoryManager(new SampleDataModelEntities()))
            {
                manager.Deleted += manager_EntityFrameworkDeleted;
                manager.Delete(person4);

                Console.WriteLine("Person count in database: " + manager.RetrieveMultiple().ToList().Count.ToString());
            }

            #endregion

            #region Example #5 : Static Operations

            Console.WriteLine("\n\nExample: #5 ------------------------------------------");

            Sample.EF4.Model.Person person5 = new Sample.EF4.Model.Person();
            person5.FirstName = "Nikola";
            person5.MiddleName = "Vlajko";
            person5.LastName = "Kocic";

            using (new EntityExecutionContext<SampleDataModelEntities>())
            {
                //Save data - Static Method
                EntityRepositoryManager<Sample.EF4.Model.Person, SampleDataModelEntities>.SaveEntityObject(person5);

                Console.WriteLine("Person count in database after static save: " + EntityRepositoryManager<Sample.EF4.Model.Person, SampleDataModelEntities>.Retrieve(p => p).ToList().Count.ToString());

                //Delete saved person
                EntityRepositoryManager<Sample.EF4.Model.Person, SampleDataModelEntities>.DeleteEntityObject(person5);

                Console.WriteLine("Person count in database after static delete:" + EntityRepositoryManager<Sample.EF4.Model.Person, SampleDataModelEntities>.Retrieve(p => p).ToList().Count.ToString());
            }

            #endregion
        }

        #region Entity Framework Event Methods
        private static void manager_EntityFrameworkCreated(object sender, DataObjectEventArgs<Sample.EF4.Model.Person> e)
        {
            Console.WriteLine();
            Console.WriteLine(MessageHelper.BuildPersonDataMessage("Created", e.DataObject.FirstName, e.DataObject.MiddleName, e.DataObject.LastName, e.DataObject.Age.ToString()));
        }

        private static void manager_EntityFrameworkDeleted(object sender, DataObjectEventArgs<Sample.EF4.Model.Person> e)
        {
            Console.WriteLine();
            Console.WriteLine(MessageHelper.BuildPersonDataMessage("Deleted", e.DataObject.FirstName, e.DataObject.MiddleName, e.DataObject.LastName, e.DataObject.Age.ToString()));
        }

        private static void manager_EntityFrameworkUpdated(object sender, DataObjectEventArgs<Sample.EF4.Model.Person> e)
        {
            Console.WriteLine();
            Console.WriteLine(MessageHelper.BuildPersonDataMessage("Updated", e.DataObject.FirstName, e.DataObject.MiddleName, e.DataObject.LastName, e.DataObject.Age.ToString()));
        }

        private static void manager_EntityFrameworkCreating(object sender, DataObjectEventArgs<Sample.EF4.Model.Person> e)
        {
            Console.WriteLine();
            Console.WriteLine(MessageHelper.BuildPersonDataMessage("Creating", e.DataObject.FirstName, e.DataObject.MiddleName, e.DataObject.LastName, e.DataObject.Age.ToString()));
        }

        private static void manager_EntityFrameworkDeleting(object sender, DataObjectEventArgs<Sample.EF4.Model.Person> e)
        {
            Console.WriteLine();
            Console.WriteLine(MessageHelper.BuildPersonDataMessage("Deleting", e.DataObject.FirstName, e.DataObject.MiddleName, e.DataObject.LastName, e.DataObject.Age.ToString()));
        }

        private static void manager_EntityFrameworkUpdating(object sender, DataObjectEventArgs<Sample.EF4.Model.Person> e)
        {
            Console.WriteLine();
            Console.WriteLine(MessageHelper.BuildPersonDataMessage("Updating", e.DataObject.FirstName, e.DataObject.MiddleName, e.DataObject.LastName, e.DataObject.Age.ToString()));
        }

        #endregion
    }
}
